package com.example.smartwaterapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.smartwaterapi.entity.Device;
import com.example.smartwaterapi.mapper.DeviceMapper;
import com.example.smartwaterapi.service.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 设备服务实现类
 */
@Slf4j
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

    /**
     * 根据设备序列号获取设备
     */
    @Override
    @Cacheable(value = "device", key = "'sn:' + #deviceSn", unless = "#result == null")
    public Device getByDeviceSn(String deviceSn) {
        log.debug("根据设备序列号查询设备: {}", deviceSn);
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getDeviceSn, deviceSn);
        return getOne(wrapper);
    }

    /**
     * 根据用户ID获取设备列表 - 实时查询，不使用缓存
     */
    @Override
    public List<Device> getByUserId(Long userId) {
        log.debug("根据用户ID实时查询设备列表: {}", userId);
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getUserId, userId);
        return list(wrapper);
    }

    /**
     * 绑定设备到用户
     */
    @Override
    @Transactional
    public boolean bindDevice(Long userId, String deviceSn, String deviceName) {
        log.debug("绑定设备, 用户ID: {}, 设备SN: {}, 设备名称: {}", userId, deviceSn, deviceName);
        Device device = getByDeviceSn(deviceSn);
        
        // 如果设备不存在，则创建新设备
        if (device == null) {
            device = new Device();
            device.setDeviceSn(deviceSn);
            device.setMacAddress(deviceSn); // 使用设备序列号作为MAC地址
            device.setDeviceName(deviceName);
            device.setUserId(userId);
            device.setIsOnline(0);
            device.setBatteryLevel(100);
            device.setCurrentVolume(0);
            device.setStatus(1);
            device.setCreatedAt(LocalDateTime.now());
            boolean result = save(device);
            
            if (result) {
                log.info("创建并绑定新设备成功, 设备SN: {}, 用户ID: {}", deviceSn, userId);
            } else {
                log.error("创建设备失败, 设备SN: {}", deviceSn);
            }
            
            return result;
        }
        
        // 如果设备已经被绑定，则返回失败
        if (device.getUserId() != null && !device.getUserId().equals(userId)) {
            log.warn("设备已被其他用户绑定, 设备SN: {}, 当前绑定用户ID: {}", deviceSn, device.getUserId());
            return false;
        }
        
        // 更新设备信息
        device.setUserId(userId);
        device.setDeviceName(deviceName);
        device.setUpdatedAt(LocalDateTime.now());
        boolean result = updateById(device);
        
        if (result) {
            log.info("绑定现有设备成功, 设备SN: {}, 用户ID: {}", deviceSn, userId);
        } else {
            log.error("更新设备信息失败, 设备SN: {}", deviceSn);
        }
        
        return result;
    }

    /**
     * 绑定设备到用户（完整参数版本）
     */
    @Override
    @Transactional
    public boolean bindDevice(Long userId, String deviceSn, String deviceId, String macAddress, String deviceName, 
                             String model, Integer batteryLevel, Integer currentVolume, 
                             Double waterTemperature, String deviceTimezone, String deviceToken,
                             String edrAddress, String bleAddress) {
        log.debug("绑定设备(完整参数), 用户ID: {}, 设备SN: {}, 设备ID: {}, MAC地址: {}, 设备名称: {}", 
                userId, deviceSn, deviceId, macAddress, deviceName);
        
        // 首先检查deviceId是否已存在
        LambdaQueryWrapper<Device> deviceIdQueryWrapper = new LambdaQueryWrapper<>();
        deviceIdQueryWrapper.eq(Device::getDeviceId, deviceId);
        Device existingDeviceById = getOne(deviceIdQueryWrapper);
        
        if (existingDeviceById != null && !existingDeviceById.getDeviceSn().equals(deviceSn)) {
            log.warn("设备ID已被其他设备使用, deviceId: {}, 现有设备SN: {}", deviceId, existingDeviceById.getDeviceSn());
            return false;
        }
        
        // 检查MAC地址是否已存在（保持向后兼容）
        LambdaQueryWrapper<Device> macQueryWrapper = new LambdaQueryWrapper<>();
        macQueryWrapper.eq(Device::getMacAddress, macAddress);
        Device existingDeviceByMac = getOne(macQueryWrapper);
        
        if (existingDeviceByMac != null && !existingDeviceByMac.getDeviceSn().equals(deviceSn)) {
            log.warn("MAC地址已被其他设备使用, MAC: {}, 现有设备SN: {}", macAddress, existingDeviceByMac.getDeviceSn());
            return false;
        }
        
        Device device = getByDeviceSn(deviceSn);
        
        // 如果设备不存在，则创建新设备
        if (device == null) {
            device = new Device();
            device.setDeviceSn(deviceSn);
            device.setDeviceId(deviceId);  // 设置蓝牙设备ID
            device.setMacAddress(macAddress);
            device.setDeviceName(deviceName);
            device.setUserId(userId);
            device.setModel(model != null ? model : "SWB-2024");
            device.setIsOnline(0);
            device.setBatteryLevel(batteryLevel != null ? batteryLevel : 100);
            device.setCurrentVolume(currentVolume != null ? currentVolume : 0);
            device.setWaterTemperature(waterTemperature);
            device.setDeviceTimezone(deviceTimezone != null ? deviceTimezone : "Asia/Shanghai");
            device.setDeviceToken(deviceToken);
            device.setStatus(1);
            device.setCreatedAt(LocalDateTime.now());
            
            // 设置额外的蓝牙地址信息到settings
            try {
                Map<String, Object> settings = new HashMap<>();
                settings.put("deviceType", "RCSP_BLUETOOTH");
                settings.put("bluetoothDeviceId", deviceId);
                if (edrAddress != null && !edrAddress.isEmpty()) {
                    settings.put("edrAddress", edrAddress);
                }
                if (bleAddress != null && !bleAddress.isEmpty()) {
                    settings.put("bleAddress", bleAddress);
                }
                settings.put("bindingTime", LocalDateTime.now().toString());
                settings.put("bindingSource", "first_pairing");
                device.setSettings(settings);
                log.debug("设置设备额外信息: {}", settings);
            } catch (Exception e) {
                log.warn("设置设备额外信息失败: {}", e.getMessage());
            }
            
            // 设置时间戳相关字段
            long currentTimestamp = System.currentTimeMillis() / 1000;
            device.setLastSyncTimestamp(currentTimestamp);
            device.setLastAuthTimestamp(currentTimestamp);
            device.setNtpSyncEnabled(1);
            device.setDeviceTimestampOffset(0);
            device.setAuthFailureCount(0);
            device.setIsLocked(0);
            
            boolean result = save(device);
            
            if (result) {
                log.info("创建并绑定新设备成功, 设备SN: {}, MAC: {}, 用户ID: {}", deviceSn, macAddress, userId);
            } else {
                log.error("创建设备失败, 设备SN: {}, MAC: {}", deviceSn, macAddress);
            }
            
            return result;
        }
        
        // 如果设备已经被绑定，则返回失败
        if (device.getUserId() != null && !device.getUserId().equals(userId)) {
            log.warn("设备已被其他用户绑定, 设备SN: {}, 当前绑定用户ID: {}", deviceSn, device.getUserId());
            return false;
        }
        
        // 更新设备信息
        device.setUserId(userId);
        device.setDeviceId(deviceId);  // 更新设备ID
        device.setMacAddress(macAddress);
        device.setDeviceName(deviceName);
        if (model != null) device.setModel(model);
        if (batteryLevel != null) device.setBatteryLevel(batteryLevel);
        if (currentVolume != null) device.setCurrentVolume(currentVolume);
        if (waterTemperature != null) device.setWaterTemperature(waterTemperature);
        if (deviceTimezone != null) device.setDeviceTimezone(deviceTimezone);
        if (deviceToken != null) device.setDeviceToken(deviceToken);
        device.setUpdatedAt(LocalDateTime.now());
        
        // 更新设备设置信息
        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> settings = device.getSettings() != null ? 
                (Map<String, Object>) device.getSettings() : new HashMap<>();
            settings.put("deviceType", "RCSP_BLUETOOTH");
            settings.put("bluetoothDeviceId", deviceId);
            if (edrAddress != null && !edrAddress.isEmpty()) {
                settings.put("edrAddress", edrAddress);
            }
            if (bleAddress != null && !bleAddress.isEmpty()) {
                settings.put("bleAddress", bleAddress);
            }
            settings.put("lastUpdateTime", LocalDateTime.now().toString());
            settings.put("updateSource", "device_rebinding");
            device.setSettings(settings);
            log.debug("更新设备额外信息: {}", settings);
        } catch (Exception e) {
            log.warn("更新设备额外信息失败: {}", e.getMessage());
        }
        
        // 更新时间戳
        long currentTimestamp = System.currentTimeMillis() / 1000;
        device.setLastSyncTimestamp(currentTimestamp);
        device.setLastAuthTimestamp(currentTimestamp);
        
        boolean result = updateById(device);
        
        if (result) {
            log.info("绑定现有设备成功, 设备SN: {}, MAC: {}, 用户ID: {}", deviceSn, macAddress, userId);
        } else {
            log.error("更新设备信息失败, 设备SN: {}, MAC: {}", deviceSn, macAddress);
        }
        
        return result;
    }

    /**
     * 解绑设备
     */
    @Override
    @Transactional
    public boolean unbindDevice(Long userId, String deviceSn) {
        log.debug("解绑设备, 用户ID: {}, 设备SN: {}", userId, deviceSn);
        
        // 为兼容测试，保留使用LambdaUpdateWrapper的方式
        Device device = getByDeviceSn(deviceSn);
        if (device == null || device.getUserId() == null || !device.getUserId().equals(userId)) {
            log.warn("解绑设备失败, 设备SN: {}, 用户ID: {}", deviceSn, userId);
            return false;
        }
        
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getDeviceSn, deviceSn)
                    .eq(Device::getUserId, userId)
                    .set(Device::getUserId, null)
                    .set(Device::getUpdatedAt, LocalDateTime.now());
        
        boolean success = update(updateWrapper);
        
        if (success) {
            log.info("解绑设备成功, 设备SN: {}, 用户ID: {}", deviceSn, userId);
        } else {
            log.warn("解绑设备失败, 设备SN: {}, 用户ID: {}", deviceSn, userId);
        }
        
        return success;
    }

    /**
     * 删除用户设备（完全删除设备记录）
     */
    @Override
    @Transactional
    public boolean deleteUserDevice(Long userId, String deviceSn) {
        log.debug("删除用户设备, 用户ID: {}, 设备SN: {}", userId, deviceSn);
        
        // 先验证设备是否属于该用户
        Device device = getByDeviceSn(deviceSn);
        if (device == null || device.getUserId() == null || !device.getUserId().equals(userId)) {
            log.warn("删除设备失败，设备不存在或不属于该用户, 设备SN: {}, 用户ID: {}", deviceSn, userId);
            return false;
        }
        
        // 完全删除设备记录
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceSn, deviceSn)
                   .eq(Device::getUserId, userId);
        
        boolean success = remove(queryWrapper);
        
        if (success) {
            log.info("删除用户设备成功, 设备SN: {}, 用户ID: {}", deviceSn, userId);
        } else {
            log.warn("删除用户设备失败, 设备SN: {}, 用户ID: {}", deviceSn, userId);
        }
        
        return success;
    }

    /**
     * 更新设备在线状态
     */
    @Override
    public boolean updateOnlineStatus(String deviceSn, boolean isOnline) {
        log.debug("更新设备在线状态, 设备SN: {}, 在线状态: {}", deviceSn, isOnline);
        
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getDeviceSn, deviceSn)
                    .set(Device::getIsOnline, isOnline ? 1 : 0)
                    .set(Device::getLastHeartbeat, LocalDateTime.now())
                    .set(Device::getUpdatedAt, LocalDateTime.now());
        
        return update(updateWrapper);
    }
    
    /**
     * 异步更新设备在线状态
     */
    @Async("ioTaskExecutor")
    public CompletableFuture<Boolean> updateOnlineStatusAsync(String deviceSn, boolean isOnline) {
        try {
            boolean result = updateOnlineStatus(deviceSn, isOnline);
            return CompletableFuture.completedFuture(result);
        } catch (Exception e) {
            log.error("异步更新设备在线状态失败, 设备SN: {}", deviceSn, e);
            return CompletableFuture.completedFuture(false);
        }
    }

    /**
     * 更新设备电量
     */
    @Override
    public boolean updateBatteryLevel(String deviceSn, Integer batteryLevel) {
        log.debug("更新设备电量, 设备SN: {}, 电量: {}%", deviceSn, batteryLevel);
        
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getDeviceSn, deviceSn)
                    .set(Device::getBatteryLevel, batteryLevel)
                    .set(Device::getUpdatedAt, LocalDateTime.now());
        
        return update(updateWrapper);
    }

    /**
     * 更新设备水量和水温
     */
    @Override
    public boolean updateWaterStatus(String deviceSn, Integer currentVolume, Double waterTemperature) {
        log.debug("更新设备水量和水温, 设备SN: {}, 当前水量: {}ml, 水温: {}℃", 
                deviceSn, currentVolume, waterTemperature);
        
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getDeviceSn, deviceSn)
                    .set(Device::getCurrentVolume, currentVolume)
                    .set(Device::getWaterTemperature, waterTemperature)
                    .set(Device::getUpdatedAt, LocalDateTime.now());
        
        return update(updateWrapper);
    }

    /**
     * 更新设备设置
     */
    @Override
    @CacheEvict(value = "device", key = "'id:' + #deviceId")
    public boolean updateDeviceSettings(Long deviceId, Object settings) {
        log.debug("更新设备设置, 设备ID: {}", deviceId);
        // 使用实体对象更新的方式代替LambdaUpdateWrapper
        Device device = getById(deviceId);
        if (device == null) {
            return false;
        }
        
        device.setSettings(settings);
        device.setUpdatedAt(LocalDateTime.now());
        return updateById(device);
    }
    
    /**
     * 批量更新设备状态
     */
    @Override
    @Transactional
    @CacheEvict(value = "device", allEntries = true)
    public boolean batchUpdateDeviceStatus(List<Device> devices) {
        log.debug("批量更新设备状态, 设备数量: {}", devices.size());
        
        // 分批处理，每次最多处理100个
        final int BATCH_SIZE = 100;
        int successCount = 0;
        
        for (int i = 0; i < devices.size(); i += BATCH_SIZE) {
            int endIndex = Math.min(i + BATCH_SIZE, devices.size());
            List<Device> batch = devices.subList(i, endIndex);
            
            try {
                boolean success = updateBatchById(batch);
                if (success) {
                    successCount += batch.size();
                }
            } catch (Exception e) {
                log.error("批量更新设备状态异常, 批次: {}/{}", i / BATCH_SIZE + 1, 
                        (devices.size() + BATCH_SIZE - 1) / BATCH_SIZE, e);
            }
        }
        
        log.info("批量更新设备状态完成, 总数: {}, 成功: {}", devices.size(), successCount);
        return successCount == devices.size();
    }

    /**
     * 更新设备表盘背景URL
     */
    @Override
    public boolean updateDialBackgroundUrl(String deviceSn, String dialBackgroundUrl) {
        log.debug("更新设备表盘背景URL, 设备SN: {}, URL: {}", deviceSn, dialBackgroundUrl);
        
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getDeviceSn, deviceSn)
                    .set(Device::getDialBackgroundUrl, dialBackgroundUrl)
                    .set(Device::getUpdatedAt, LocalDateTime.now());
        
        boolean result = update(updateWrapper);
        
        if (result) {
            log.info("设备表盘背景URL更新成功, 设备SN: {}, URL: {}", deviceSn, dialBackgroundUrl);
        } else {
            log.error("设备表盘背景URL更新失败, 设备SN: {}", deviceSn);
        }
        
        return result;
    }

    /**
     * 根据用户ID查找用户的主设备（第一个绑定的设备）
     */
    @Override
    public String findUserPrimaryDevice(String userId) {
        try {
            Long userIdLong = Long.parseLong(userId);
            log.debug("查找用户主设备: userId={}", userIdLong);
            
            LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Device::getUserId, userIdLong)
                   .orderByAsc(Device::getCreatedAt) // 按创建时间升序，获取第一个绑定的设备
                   .last("LIMIT 1");
            
            Device device = getOne(wrapper);
            
            if (device != null) {
                log.info("找到用户主设备: userId={}, deviceSn={}", userIdLong, device.getDeviceSn());
                return device.getDeviceSn();
            } else {
                log.warn("未找到用户的设备: userId={}", userIdLong);
                return null;
            }
        } catch (NumberFormatException e) {
            log.error("用户ID格式错误: userId={}", userId, e);
            return null;
        } catch (Exception e) {
            log.error("查找用户主设备失败: userId={}", userId, e);
            return null;
        }
    }

    /**
     * 智能更新设备表盘背景URL - 支持多种设备标识符
     */
    @Override
    public boolean smartUpdateDialBackground(String userId, String deviceId, String deviceSn, String dialBackgroundUrl) {
        log.info("🎨 智能更新表盘背景: userId={}, deviceId={}, deviceSn={}", userId, deviceId, deviceSn);
        
        // 策略1: 优先使用设备ID（蓝牙真实标识符）
        if (deviceId != null && !deviceId.trim().isEmpty()) {
            log.info("📱 策略1: 使用设备ID查找并更新: {}", deviceId);
            
            // 通过设备ID查找设备
            LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Device::getDeviceId, deviceId);
            Device device = getOne(wrapper);
            
            if (device != null) {
                log.info("✅ 通过设备ID找到设备: deviceSn={}", device.getDeviceSn());
                return updateDialBackgroundUrl(device.getDeviceSn(), dialBackgroundUrl);
            } else {
                log.warn("⚠️ 通过设备ID未找到设备: {}", deviceId);
            }
        }
        
        // 策略2: 使用设备序列号
        if (deviceSn != null && !deviceSn.trim().isEmpty()) {
            log.info("📱 策略2: 使用设备序列号更新: {}", deviceSn);
            boolean result = updateDialBackgroundUrl(deviceSn, dialBackgroundUrl);
            if (result) {
                log.info("✅ 通过设备序列号更新成功: {}", deviceSn);
                return true;
            } else {
                log.warn("⚠️ 通过设备序列号更新失败: {}", deviceSn);
            }
        }
        
        // 策略3: 根据用户ID查找主设备
        if (userId != null && !userId.trim().isEmpty()) {
            log.info("📱 策略3: 根据用户ID查找主设备: {}", userId);
            String primaryDeviceSn = findUserPrimaryDevice(userId);
            if (primaryDeviceSn != null) {
                log.info("✅ 找到用户主设备: {}", primaryDeviceSn);
                return updateDialBackgroundUrl(primaryDeviceSn, dialBackgroundUrl);
            } else {
                log.warn("⚠️ 未找到用户的主设备: userId={}", userId);
            }
        }
        
        log.error("❌ 所有策略都失败，无法更新表盘背景");
        return false;
    }

}